package com.mrxu.monitor.service;

import com.alibaba.fastjson.JSONObject;
import com.mrxu.monitor.config.BusinessCodeConfig;
import com.mrxu.monitor.config.MonitorProperties;
import com.mrxu.monitor.notice.MessageCenterService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 该类命名以 _ 开头目的是让拦截器放最后执行
 */
@Slf4j
@Component
@ControllerAdvice
public class _ApiResponseBodyAdvice implements ResponseBodyAdvice {

    @Autowired
    private MonitorProperties monitorProperties;

    @Autowired
    private MessageCenterService messageCenterService;

    @Autowired
    private ReportService reportService;

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        BusinessCodeConfig config = monitorProperties.getBusinessCode();
        if(!monitorProperties.isEnable() || config == null || !config.isEnable()) {
            return false;
        }
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        if((body == null) || (body instanceof Resource)) {
            return body;
        }

        // 这段代码应该是没用的，因为在上个方法已经判断guo了，如果为空根本不会进来
        BusinessCodeConfig config = monitorProperties.getBusinessCode();
        if(!monitorProperties.isEnable() || config == null || !config.isEnable()) {
            return body;
        }

        // 如果是基本类型，不计算
        if(body.getClass().getPackage().getName().equals("java.lang")) {
            return body;
        }

        String codeName = config.getCodeName();
        try {
            Object code = null;

            // 用这种方式 效率低些但是更严谨
            JSONObject result = (JSONObject) JSONObject.toJSON(body);
            code = result.get(codeName);

            /*Field field = body.getClass().getDeclaredField(codeName);
            if(field.getModifiers() == 1) { // public
                code = field.get(body);
            }
            else {
                Method method = body.getClass().getMethod("get"+firstToUpper(codeName));
                if(method.getModifiers() == 1) { // public
                    code = method.invoke(body);
                }
            }*/

            if(code != null) {
                String codeStr = code.toString();
                // 业务失败
                if(!codeStr.equals(config.getSuccessCode())) {
                    Map<String, String> errorCodeNotice = config.getErrorCodeNotice();
                    if(errorCodeNotice != null && errorCodeNotice.containsKey(codeStr)) {
                        messageCenterService.sendNoticeMsg(errorCodeNotice.get(codeStr),codeStr);
                    }
                    reportService.addBusinessErrorCount();
                }
            }
            else {
                log.error("业务状态码配置错误,未能获取到状态码值");
            }

        } catch (Exception e) {
            log.error("业务状态码配置异常",e);
        }
        return body;
    }

    private String firstToUpper(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

}
